package com.intramirror.product.service.impl;

import com.intramirror.core.common.exception.ValidateException;
import com.intramirror.core.common.response.ErrorResponse;
import com.intramirror.product.entity.Product;
import com.intramirror.product.entity.Spu;
import com.intramirror.product.entity.SpuAggregateLog;
import com.intramirror.product.entity.SpuExceptionProduct;
import com.intramirror.product.entity.SpuOperateLog;
import com.intramirror.product.exception.BusinessException;
import com.intramirror.product.mapper.ProductMapper;
import com.intramirror.product.mapper.SpuAggregateLogMapper;
import com.intramirror.product.mapper.SpuExceptionProductMapper;
import com.intramirror.product.mapper.SpuMapper;
import com.intramirror.product.mapper.SpuOperateLogMapper;
import com.intramirror.product.service.IAggregateService;
import com.intramirror.product.service.ISpuService;
import com.intramirror.product.utils.AggregateRuleManagement;
import com.intramirror.product.utils.ConvertUtil;
import com.intramirror.product.utils.SeasonUtil;
import com.intramirror.product.utils.SpuLogUtil;
import com.intramirror.utils.transform.JsonTransformUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * SKU服务
 */
@Service
public class SpuServiceImpl implements ISpuService {

    private final static Logger LOGGER = LoggerFactory.getLogger(SpuServiceImpl.class);

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private SpuAggregateLogMapper spuAggregateLogMapper;

    @Autowired
    SpuExceptionProductMapper spuExceptionProductMapper;

    @Autowired
    SpuOperateLogMapper spuOperateLogMapper;

    @Autowired
    IAggregateService aggregateService;

    public Spu getSpuById(Long spuId) {
        return spuMapper.selectByPrimaryKey(spuId);
    }

    @Override
    public List<Map<String, Object>> getSpuListByCond(Map<String, Object> condMap) {
        return spuMapper.getSpuListByCond(condMap);
    }

    @Transactional
    @Override
    public void deleteSpu(Long spuId) {
        spuMapper.deleteByPrimaryKey(spuId);
        productMapper.unbindProductSpu(spuId);
    }

    @Override
    @Transactional
    public int deleteSpus(List<Long> spuIdList) {
        spuMapper.batchDeleteSpus(spuIdList);
        productMapper.batchUnbindProductSpu(spuIdList);
        return 0;
    }

    @Override
    public Spu getSpuByDesignerAndColorCode(String designerId, String colorCode) {
        Spu spu = new Spu();
        spu.setDesignerId(designerId);
        spu.setColorCode(colorCode);
        List<Spu> listSpu = spuMapper.selectByParameter(spu);
        if (listSpu.size() > 0) {
            return listSpu.get(0);
        } else {
            return null;
        }
    }

    @Override
    @Transactional
    public void updateSpuById(Spu spu) {
        //对比电商图，如果变化，就算是运营编辑过电商图
        Spu s = spuMapper.selectByPrimaryKey(spu.getSpuId());
        if (!s.getBoutiqueImg().equals(spu.getBoutiqueImg())) {
            spu.setVendorId(-1L);
        }
        spu.setCoverImg(dealCoverImg(spu));
        spu.setDescImg(dealDescImg(spu));
        spuMapper.updateByPrimaryKeySelective(spu);
    }

    //spu并入新product时，检查现有图片和新product图片的替换规则
    @Override
    @Transactional
    public boolean dealBoutiqueImg(Long srcSpuId, Long targetSpuId, Long productId) {
        Product product = productMapper.selectByPrimaryKey(productId);
        if (product == null) {
            throw new ValidateException(new ErrorResponse("找不到Product!"));
        }

        //刷新目标spu的图片
        if (targetSpuId != null) {
            refreshTargetSpu(targetSpuId, product);
        }

        //刷新原始spu的图片
        if (srcSpuId != null) {
            refreshSrcSpu(srcSpuId, product);
        }
        return true;
    }

    private Product filterBestPrd(Product oldBestPrd, Map<String, Object> candidate, Long productId) {
        Product newBestPrd = new Product();
        Map<Long, Integer> boutiqueImgSortMap = AggregateRuleManagement.getInstance().getBoutiqueImgSortMap();
        Integer newSort = boutiqueImgSortMap.get((Long) candidate.get("vendorId")) != null ? boutiqueImgSortMap.get((Long) candidate.get("vendorId")) : 10002;
        Integer oldSort = boutiqueImgSortMap.get(oldBestPrd.getVendorId()) != null ? boutiqueImgSortMap.get(oldBestPrd.getVendorId()) : 10001;

        //排除掉要move出去的product
        if (oldBestPrd.getProductId() == -1 || (newSort < oldSort && productId.longValue() != ConvertUtil.toLong(candidate.get("productId")).longValue())) {
            newBestPrd.setProductId((Long) candidate.get("productId"));
            newBestPrd.setCoverImg((String) candidate.get("coverImg"));
            newBestPrd.setVendorId((Long) candidate.get("vendorId"));
            return newBestPrd;
        } else {
            return null;
        }
    }

    private void refreshSrcSpu(Long srcSpuId, Product product) {
        LOGGER.debug("Start to refreshSrcSpu!");
        Spu s = spuMapper.selectByPrimaryKey(srcSpuId);

        if (s == null) {
            throw new ValidateException(new ErrorResponse("找不到原始Spu!"));
        }

        Map<String, Object> condMap = new HashMap<>();
        condMap.put("spuId", srcSpuId);
        List<Map<String, Object>> listPrd = productMapper.getProductBySpuId(condMap);

        Product bestPrd = new Product();
        bestPrd.setProductId(-1L);
        bestPrd.setVendorId(10001L);
        bestPrd.setCoverImg("");

        // 大于3张图片中先筛选
        for (Map<String, Object> map : listPrd) {
            String sCoverImg = (String) map.get("coverImg");
            List<String> listCoverImg = sImgToList(sCoverImg);
            if (listCoverImg.size() < 3) {
                continue;
            }

            Product newBestPrd = filterBestPrd(bestPrd, map, product.getProductId());
            bestPrd = newBestPrd != null ? newBestPrd : bestPrd;
        }
        LOGGER.debug("[image filter rule1] boutique num >= 3, find new productId:{},vendorId:{}", bestPrd.getProductId(), bestPrd.getVendorId());

        //都是小于3张的图, 就选一个优先级高的，有图的
        if (bestPrd.getProductId() == -1) {
            for (Map<String, Object> map : listPrd) {
                String sCoverImg = (String) map.get("coverImg");
                List<String> listCoverImg = sImgToList(sCoverImg);
                if (listCoverImg.size() <= 0) {
                    continue;
                }

                Product newBestPrd = filterBestPrd(bestPrd, map, product.getProductId());
                bestPrd = newBestPrd != null ? newBestPrd : bestPrd;
            }
            LOGGER.debug("[image filter rule2] boutique num < 3, find new productId:{},vendorId:{}", bestPrd.getProductId(), bestPrd.getVendorId());
        }

        s.setBoutiqueImg(bestPrd.getCoverImg());
        s.setVendorId(bestPrd.getVendorId());
        s.setCoverImg(dealCoverImg(s));
        s.setDescImg(dealDescImg(s));
        s.setUpdatedAt(null);
        spuMapper.updateByPrimaryKeySelective(s);
    }

    private void refreshTargetSpu(Long targetSpuId, Product p) {
        Spu s = spuMapper.selectByPrimaryKey(targetSpuId);

        if (s == null) {
            throw new ValidateException(new ErrorResponse("找不到目标Spu!"));
        }

        Map<Long, Integer> boutiqueImgSortMap = AggregateRuleManagement.getInstance().getBoutiqueImgSortMap();
        //找不到排序位置的vendor id则把优先级定成最低，不用它的图片
        Integer spuSort = boutiqueImgSortMap.get(s.getVendorId()) != null ? boutiqueImgSortMap.get(s.getVendorId()) : 10001;
        Integer prdSort = boutiqueImgSortMap.get(p.getVendorId()) != null ? boutiqueImgSortMap.get(p.getVendorId()) : 10000;

        LOGGER.debug("Get prdSort:{}, spuSort:{}", prdSort, spuSort);
        List<String> listImg = sImgToList(p.getCoverImg());
        List<String> listTargetImg = sImgToList(s.getBoutiqueImg());

        // 新商品图片数量大于3张 且优先级高于原来spu的图片优先级
        if (listTargetImg.size() <= 0 || (listImg.size() >= 3 && (s.getImgModified() == null || !s.getImgModified()) && (prdSort < spuSort
                || listTargetImg.size() < 3))) {
            s.setBoutiqueImg(p.getCoverImg());
            s.setUpdatedAt(null);
            s.setCoverImg(dealCoverImg(s));
            s.setDescImg(dealDescImg(s));
            s.setVendorId(p.getVendorId());
            s.setSeasonCode(p.getSeasonCode());
        }
        spuMapper.updateByPrimaryKeySelective(s);
    }

    @Override
    public String dealCoverImg(Spu s) {
        String sBoutiqueImg = s.getBoutiqueImg();
        String sModelImg = s.getModelImg();
        String sStreetImg = s.getStreetImg();

        List<String> listBoutiqueImg = sImgToList(sBoutiqueImg);
        List<String> listModelImg = sImgToList(sModelImg);
        List<String> listStreetImg = sImgToList(sStreetImg);

        List<String> listCoverImg = new ArrayList<>();

        //第一张放电商图
        if (listBoutiqueImg.size() > 0) {
            listCoverImg.add(listBoutiqueImg.get(0));
        }

        //cover img最多9张
        appendImg(listCoverImg, listStreetImg, 0, 9);
        appendImg(listCoverImg, listModelImg, 0, 9);
        appendImg(listCoverImg, listBoutiqueImg, 1, 9);

        return JsonTransformUtil.toJson(listCoverImg);
    }

    @Override
    @Transactional
    public void updateSpu(Spu spu) {
        spuMapper.updateByPrimaryKeySelective(spu);
    }

    @Override
    public String dealDescImg(Spu s) {
        String sBoutiqueImg = s.getBoutiqueImg();
        String sModelImg = s.getModelImg();
        String sStreetImg = s.getStreetImg();

        List<String> listBoutiqueImg = sImgToList(sBoutiqueImg);
        List<String> listModelImg = sImgToList(sModelImg);
        List<String> listStreetImg = sImgToList(sStreetImg);

        List<String> listDescImg = new ArrayList<>();

        //desc img最多27张
        appendImg(listDescImg, listBoutiqueImg, 0, 27);
        appendImg(listDescImg, listModelImg, 0, 27);
        appendImg(listDescImg, listStreetImg, 0, 27);

        return JsonTransformUtil.toJson(listDescImg);
    }

    private void appendImg(List<String> targetImgList, List<String> srcImgList, Integer startNum, Integer stopNum) {
        int i = startNum;
        while (targetImgList.size() < stopNum) {
            if (srcImgList.size() > i) {
                targetImgList.add(srcImgList.get(i));
            } else {
                break;
            }
            i++;
        }
    }

    @Override
    public List<String> sImgToList(String sImg) {
        List<String> listImg = new ArrayList<>();
        if (sImg != null) {
            listImg = JsonTransformUtil.readValue(sImg, List.class);
        }
        return listImg != null ? listImg : new ArrayList<>();
    }

    @Override
    public Spu exactMatchWithExistsSpu(Product product) {
        List<Spu> listSpu = spuMapper.filterSpuDesignerCodeByProduct(product);
        if (listSpu != null && listSpu.size() > 0) {
            return listSpu.get(0);
        }

        //        listSpu = spuMapper.filterSpuDesignerId(product.getDesignerId() + product.getColorCode());
        //        if (listSpu != null && listSpu.size() > 0) {
        //            return listSpu.get(0);
        //        }

        //        listSpu = spuMapper.filterSpuDesignerId(product.getDesignerId());
        //        if (listSpu != null && listSpu.size() > 0) {
        //            for (Spu spu : listSpu) {
        //                if (spu.getColorCode().startsWith(product.getColorCode()) || spu.getColorCode().endsWith(product.getColorCode()) || product.getColorCode()
        //                        .startsWith(spu.getColorCode()) || product.getColorCode().endsWith(spu.getColorCode())) {
        //                    return spu;
        //                }
        //            }
        //        }

        LOGGER.debug("Could not find spu for exact match.");
        return null;
    }

    @Override
    public List<Spu> inexactMatchWithExistsSpu(Product product) {
        List<Spu> listSpu = spuMapper.filterSpuDesignerId(product.getDesignerId());
        return listSpu;
        //        if (listSpu != null && listSpu.size() > 0) {
        //            for (Spu spu : listSpu) {
        //                if (spu.getColorCode().startsWith(product.getColorCode()) || spu.getColorCode().endsWith(product.getColorCode()) || product.getColorCode()
        //                        .startsWith(spu.getColorCode()) || product.getColorCode().endsWith(spu.getColorCode())) {
        //                    return null;
        //                }
        //            }
        //            return listSpu;
        //        } else {
        //            LOGGER.debug("Could not find spu for inexact match.");
        //            return null;
        //        }
    }

    @Transactional
    @Override
    public void addSpuExceptionProduct(Long userId, SpuExceptionProduct spuExceptionProduct) {
        spuExceptionProduct.setUserId(userId);
        spuExceptionProductMapper.addSpuExceptionProduct(spuExceptionProduct);

        //
        Spu newSpu = spuMapper.selectByPrimaryKey(spuExceptionProduct.getSpuId());
        List<Product> listProduct = productMapper.getAllProductForSpu(spuExceptionProduct.getSpuId());
        List<Product> leftProduct = new ArrayList<>();
        for (Product p : listProduct) {
            if (p.getProductId().longValue() == spuExceptionProduct.getProductId()) {
                continue;
            }
            leftProduct.add(p);
        }

        if (leftProduct.size() > 0) {
            newSpu = updateSpuBoutiqueImg(newSpu, leftProduct);
            spuMapper.updateByPrimaryKeySelective(newSpu);
        }

        // dealBoutiqueImg(spuExceptionProduct.getSpuId(), null, spuExceptionProduct.getProductId());
        productMapper.removeProductSpuInfo(spuExceptionProduct.getProductId());
        SpuOperateLog log = SpuLogUtil.buildSpuExceptionProduct(userId, spuExceptionProduct);
        spuOperateLogMapper.addSpuOperateLog(log);
    }

    @Override
    public void processSpuWithSeason() {
        final int pageSize = 1000;
        int pageNo = 0;
        List<Spu> listSpu = spuMapper.selectSpuList(0, pageSize);

        while (listSpu != null && listSpu.size() > 0) {
            for (Spu spu : listSpu) {
                processOneSpuWithSeason(spu);
            }
            pageNo++;
            listSpu = spuMapper.selectSpuList(pageNo * pageSize, pageSize);
        }

    }

    @Transactional
    public void processOneSpuWithSeason(Spu spu) {
        if (spu == null) {
            return;
        }

        List<Product> listProduct = productMapper.getAllProductForSpu(spu.getSpuId());
        Map<String, List<Product>> seasonProducts = new HashMap<>();
        String newestSeason = null;
        for (Product product : listProduct) {
            String seasonCode = product.getSeasonCode();
            if ("CarryOver".equalsIgnoreCase(seasonCode)) {
                seasonCode = SeasonUtil.carryOverToNewSeasonCode();
            }

            if (seasonProducts.containsKey(seasonCode)) {
                seasonProducts.get(seasonCode).add(product);
            } else {
                List<Product> sameSeasonProduct = new ArrayList<>();
                sameSeasonProduct.add(product);
                seasonProducts.put(seasonCode, sameSeasonProduct);
            }
            newestSeason = SeasonUtil.getNewerSeason(newestSeason, seasonCode);
        }

        if (seasonProducts.size() == 1) {
            String season = seasonProducts.entrySet().stream().findFirst().map(Map.Entry::getKey).orElse(null);
            if (season != null) {
                LOGGER.info("====>SPU 只有Season数等于1：修改SPU的season。");
                updateSpuSeason(spu, season);
            }
        } else {
            Spu copySpu = copySpuInfo(spu);
            for (Map.Entry<String, List<Product>> entry : seasonProducts.entrySet()) {
                if (!entry.getKey().equals(newestSeason)) {
                    // copy new spu
                    Spu newSpu = copySpuInfo(copySpu);
                    newSpu.setSeasonCode(entry.getKey());
                    newSpu = updateSpuBoutiqueImg(newSpu, entry.getValue());
                    spuMapper.insertSelective(newSpu);
                    for (Product product : entry.getValue()) {
                        productMapper.updateProductSpuInfo(product.getProductId(), newSpu.getSpuId());
                    }
                    LOGGER.info("====>SPU有多个Season：处理season[{}], insert new spu {}, boutique_img {} cover_img {}.", entry.getKey(), newSpu,
                            newSpu.getBoutiqueImg(), newSpu.getCoverImg());
                } else {
                    spu.setSeasonCode(entry.getKey());
                    spu = updateSpuBoutiqueImg(spu, entry.getValue());
                    spuMapper.updateByPrimaryKeySelective(spu);

                    LOGGER.info("====>SPU有多个Season：处理season[{}], insert new spu {}, boutique_img {} cover_img {}.", entry.getKey(), spu, spu.getBoutiqueImg(),
                            spu.getCoverImg());
                }
            }
        }

    }

    private Spu copySpuInfo(Spu spu) {
        if (spu == null) {
            return null;
        }

        Spu newSpu = new Spu();
        newSpu.setDesignerId(spu.getDesignerId());
        newSpu.setColorCode(spu.getColorCode());
        newSpu.setDesignerColor(spu.getDesignerColor());
        newSpu.setSpuName(spu.getSpuName());
        newSpu.setSpuDescription(spu.getSpuDescription());
        newSpu.setBoutiqueImg(spu.getBoutiqueImg());
        newSpu.setStreetImg(spu.getStreetImg());
        newSpu.setModelImg(spu.getModelImg());
        newSpu.setCoverImg(spu.getCoverImg());
        newSpu.setBrandName(spu.getBrandName());
        newSpu.setBrandId(spu.getBrandId());
        newSpu.setImgModified(spu.getImgModified());
        newSpu.setDescModify(spu.getDescModify());
        newSpu.setDescImg(spu.getDescImg());
        newSpu.setDimension(spu.getDimension());
        newSpu.setComposition(spu.getComposition());
        newSpu.setEnabled(spu.getEnabled());
        newSpu.setVendorId(spu.getVendorId());
        newSpu.setCreatedAt(new Date());
        newSpu.setUpdatedAt(new Date());
        newSpu.setSeasonCode(spu.getSeasonCode());
        return newSpu;
    }

    private Integer getLesserSort(Integer sort1, Integer sort2) {
        if (sort1 == null || sort2 == null) {
            return sort1 == null ? sort2 : sort1;
        }
        if (sort1 > sort2) {
            return sort2;
        } else {
            return sort1;
        }
    }

    // private Product getNew
    private Product getNewestProduct(List<Product> listProduct) {
        if (listProduct == null || listProduct.size() == 0) {
            return null;
        }

        for (Product product : listProduct) {
            List<String> imgList = sImgToList(product.getCoverImg());
            if (product.getImgModified() != null && product.getImgModified() && imgList != null && imgList.size() > 2) {
                // 有实拍
                return product;
            }
        }

        // 按照新季的vendor顺序取boutique image
        Map<Long, Integer> boutiqueImgSortMap = AggregateRuleManagement.getInstance().getBoutiqueImgSortMap();
        //找不到排序位置的vendor id则把优先级定成最低，不用它的图片
        Product newSeasonProduct = null;
        Integer sort = null;
        for (Product product : listProduct) {
            Integer productSort = boutiqueImgSortMap.get(product.getVendorId());
            List<String> imgList = sImgToList(product.getCoverImg());
            sort = getLesserSort(sort, productSort);
            if ((sort == null || (productSort != null && sort.intValue() == productSort)) && imgList != null && imgList.size() > 2) {

                newSeasonProduct = product;
            }
        }

        if (newSeasonProduct != null) {
            LOGGER.info("The best boutique image {} == {}", newSeasonProduct.getCoverImg(), newSeasonProduct.getImgModified());
        } else {
            LOGGER.info("Not have best boutique image.");
        }
        return newSeasonProduct;
    }

    private void updateSpuSeason(Spu spu, String seasonCode) {
        Spu newSpu = new Spu();
        newSpu.setSeasonCode(seasonCode);
        newSpu.setSpuId(spu.getSpuId());
        spuMapper.updateByPrimaryKeySelective(newSpu);
        SpuLogUtil.buildSaveSpuLog(-1L, spu, newSpu);
    }

    /**
     * 剩余商品如果有实拍，则按照2+n替换电商图和模特图
     * 如果没有实拍，按照vendor优先级取电商图，如果没有取到，则不更改
     * @param spu
     *         需要重新计算的SPU
     * @param listProduct
     *         SPU剩余的product
     * @return 重新计算boutique image 和 model image 的SPU
     */
    private Spu updateSpuBoutiqueImg(Spu spu, List<Product> listProduct) {
        Product productBoutiqueImg = getNewestProduct(listProduct);
        if (productBoutiqueImg != null) {
            List<String> imgList = sImgToList(productBoutiqueImg.getCoverImg());
            if (productBoutiqueImg.getImgModified() != null && productBoutiqueImg.getImgModified()) {
                spu.setBoutiqueImg(JsonTransformUtil.toJson(imgList.subList(0, 2)));
                spu.setModelImg(JsonTransformUtil.toJson(imgList.subList(2, imgList.size())));
                spu.setVendorId(-1L);
                spu.setImgModified(true);
                LOGGER.info("商品有实拍，按照2+n替换电商图和模特图");
            } else {
                spu.setBoutiqueImg(JsonTransformUtil.toJson(imgList));
                spu.setVendorId(productBoutiqueImg.getVendorId());
                LOGGER.info("商品没有实拍，按照顺序取电商图");
            }
            spu.setCoverImg(dealCoverImg(spu));
            spu.setDescImg(dealDescImg(spu));
        }
        return spu;
    }

    @Override
    public Map<String, Object> countSpu(Map<String, Object> condMap) {
        return spuMapper.countSpuByCond(condMap);
    }

    @Override
    public Spu findExistsSpuByDesignerId(String designerId) {
        return spuMapper.findExistsSpuByDesignerId(designerId);
    }

    @Override
    public void saveAggregateLog(SpuAggregateLog spuAggregateLog) {
        spuAggregateLogMapper.insertSelective(spuAggregateLog);
    }

    @Transactional
    public void unbindProductSpu(Long spuId, Long productId) {
        dealBoutiqueImg(spuId, null, productId);
        productMapper.removeProductSpuInfo(productId);
    }

    @Override
    @Transactional
    public void rebindingProductSpu(Product product, Spu spu) {
        //获取除了已解绑的商品之外的所有聚合到spu下的商品
        Long productId = product.getProductId();
        List<Product> listProduct = productMapper.getAllProductForSpu(spu.getSpuId());
        List<Product> leftProduct = new ArrayList<>();
        for (Product p : listProduct) {
            if (p.getProductId().longValue() == productId) {
                continue;
            }
            leftProduct.add(p);
        }

        //根据规则重新处理spu的图片
        if (leftProduct.size() > 0) {
            spu = updateSpuBoutiqueImg(spu, leftProduct);
            spuMapper.updateByPrimaryKeySelective(spu);
        }
        productMapper.removeProductSpuInfo(productId);

        //商品聚合到新的SPU
        try {
            aggregateService.aggregateProduct(product);
        } catch (BusinessException e) {
            LOGGER.error("Could not aggregate product {}.", product.getProductId());
        }
    }
}
